#include "server.h"
#include <iostream>

//libevent回调函数
void G_CALLBACK_FUN(int fd, short ev, void* arg)
{
    if( ev & EV_READ)
    {
        Event_Obj* p = (Event_Obj*)arg;
        if(p != nullptr)
        {
            p->Event_Callback();
        }
    }
}

bool Mysql_Cli::Connect_Mysql_Ser(const string user,const string passwd,const string host,
                                  const string dbname,const unsigned int port)
{
    if(mysql_init(&mysql_con) == NULL)
    {
        return false;
    }
    if(mysql_real_connect(&mysql_con,host.c_str(),user.c_str(),passwd.c_str(),dbname.c_str(),port,NULL,0) == NULL)
    {
        cout<<"mysql connect error"<<endl;
        return false;
    }
    return true;
}
bool Mysql_Cli::Mysql_ZC_User(string tel,string username,string userpasswd)
{
    if(tel.empty()||username.empty())
    {
        return false;
    }
    string sql = string("insert into user_info values(0,'") + tel + string("','") + username + string("','") + userpasswd + string("','1',curdate())");
    //cout<<sql<<endl;
    if(mysql_query(&mysql_con,sql.c_str()) != 0)
    {
        cout<<"mysql_query error"<<endl;
        return false;
    }
    return true;
}
bool Mysql_Cli::Mysql_DL_User(string tel,string userpasswd,string& username)
{
    if(tel.empty()||userpasswd.empty())
    {
        return false;
    }
    string sql = string("select Name,Passwd from user_info where Tel='") + tel + string("'");
    cout<<sql<<endl;
    if(mysql_query(&mysql_con,sql.c_str()) != 0)
    {
        cout<<"mysql_query error"<<endl;
        return false;
    }
    MYSQL_RES* r = mysql_store_result(&mysql_con);
    if(r == NULL)
    {
        cout<<"mysql_res error"<<endl;
        return false;
    } 

    int num = mysql_num_rows(r);
    if(num == 0)
    {
        cout<<"没有查询到记录"<<endl;
        
        return false;
    }

    MYSQL_ROW row = mysql_fetch_row(r); //取一行结果集
    if(userpasswd.compare(row[1]) != 0)
    {
        cout<<"手机号不符合"<<endl;
        return false;
    }

    username = row[0]; //用户名 row[1]是密码
    
    mysql_free_result(r);
    return true;
}
bool Mysql_Cli::Mysql_CK_Ticket(Json::Value &val)
{
    string sql = "select * from ticket_table where Status=1;";
    if(mysql_query(&mysql_con,sql.c_str()) != 0)
    {
        cout<<"mysql_query error"<<endl;
        return false;
    }
    MYSQL_RES* r = mysql_store_result(&mysql_con);
    if(r == NULL)
    {
        cout<<"mysql_res error"<<endl;
        return false;
    }
    int num = mysql_num_rows(r); //查看有多少行记录
    val["status"] = "OK";
    val["num"] = num;
    if(num == 0)
    {
        mysql_free_result(r);
        return true;
    }

    for(int i=0;i<num;i++)
    {
        Json::Value tmp;
        MYSQL_ROW row = mysql_fetch_row(r); //取一行结果集
        tmp["tk_id"] = row[0];
        tmp["tk_name"] = row[1];
        tmp["tk_max"] = row[2];
        tmp["tk_num"] = row[3];
        tmp["tk_day"] = row[4];
        val["tk_arr"].append(tmp); //json数组
    }

    mysql_free_result(r);
    return true;
}
bool Mysql_Cli::Mysql_YD_Ticket(string tel,string tk_id)
{
    //开启事务
    if(mysql_query(&mysql_con,"begin") != 0)
    {
        cout<<"事务开启失败"<<endl;
        return false;
    }

    string sql_TkMax = string("select Tk_Max,Tk_Num from ticket_table where Tk_Id=") + tk_id;
    if(mysql_query(&mysql_con,sql_TkMax.c_str()) != 0)
    {
        cout<<"sql_TkMax查询失败"<<endl;
        return false;
    }

    MYSQL_RES* r = mysql_store_result(&mysql_con);
    if( r == NULL )
    {
        return false;
    }

    MYSQL_ROW row = mysql_fetch_row(r); 
    int Tk_Max = atoi(row[0]);
    int Tk_Num = atoi(row[1]);
    //检查票是否有剩余
    if(Tk_Num >= Tk_Max)
    {
        mysql_query(&mysql_con,"commit");
        return false;
    }

    Tk_Num++;
    string sql_setNum = string("update ticket_table set Tk_Num=") + to_string(Tk_Num) + string(" where Tk_Id=") + tk_id;
    if(mysql_query(&mysql_con,sql_setNum.c_str()) != 0)
    {
        mysql_query(&mysql_con,"rollback"); //事务回滚
        return false;
    }

    string sql_yd = string("insert into Yd_table values(0,'") + tel + string("',") + tk_id + string(",now(),'1')");
    if(mysql_query(&mysql_con,sql_yd.c_str()) != 0)
    {
        mysql_query(&mysql_con,"rollback"); //事务回滚
        return false;
    }

    mysql_query(&mysql_con,"commit");
    return true;
}
bool Mysql_Cli::Mysql_CKYY_User(string tel,Json::Value &val)
{
    string sql = string("select Yd_Id,Tk_Name,DateTime from Yd_table,ticket_table where Yd_table.Tk_Id=ticket_table.Tk_Id and Yd_table.Tel=") + tel;
    if(mysql_query(&mysql_con,sql.c_str()) != 0)
    {
        cout<<"CKYY查询失败"<<endl;
        return false;
    }
    MYSQL_RES* r = mysql_store_result(&mysql_con);
    if( r == NULL )
    {
        return false;
    }

    int num = mysql_num_rows(r); //查看有多少行记录
  
    val["status"] = "OK";
    val["num"] = num;
    if( num == 0 )
    {
        mysql_free_result(r);
        return true;
    }
    for(int i=0;i<num;i++)
    {
        Json::Value tmp;
        MYSQL_ROW row = mysql_fetch_row(r); //取一行结果集
        //tmp["tk_id"] = row[0];
        tmp["yd_id"] = row[0];
        tmp["tk_name"] = row[1];
        tmp["tk_datetime"] = row[2];
        val["tk_arr"].append(tmp); //json数组
    }
    mysql_free_result(r);
    return true;
}
bool Mysql_Cli::Mysql_QXYY_User(string yd_id)
{
    //开启事务
    if(mysql_query(&mysql_con,"begin") != 0)
    {
        cout<<"事务开启失败"<<endl;
        return false;
    }

    //修改ticket_table表中信息
    string sql_sel = string("select ticket_table.Tk_Id,Tk_Num from ticket_table,Yd_table where Yd_Id =") + yd_id + string(" and Yd_table.Tk_id=ticket_table.Tk_Id");
    if(mysql_query(&mysql_con,sql_sel.c_str()) != 0)
    {
        cout<<"查询 error"<<endl;
        return false;
    }
    MYSQL_RES* r = mysql_store_result(&mysql_con);
    if( r == NULL )
    {
        cout<<"mysql_res err"<<endl;
        return false;
    }
    MYSQL_ROW row = mysql_fetch_row(r); 
    mysql_free_result(r);
    int Tk_Id = atoi(row[0]);
    int Tk_Num = atoi(row[1]);
    Tk_Num--;
    string sql_setNum = string("update ticket_table set Tk_Num=") + to_string(Tk_Num) + string(" where Tk_Id=") + to_string(Tk_Id);
    if(mysql_query(&mysql_con,sql_setNum.c_str()) != 0)
    {
        cout<<"setNum error"<<endl;
        mysql_query(&mysql_con,"rollback"); //事务回滚
        return false;
    }

    //删除yd_table表中一行信息
    string sql = string("delete from Yd_table where Yd_Id=") + yd_id;
    if(mysql_query(&mysql_con,sql.c_str()) != 0)
    {
        cout<<"mysql_query error"<<endl;
        mysql_query(&mysql_con,"rollback"); //事务回滚
        return false;
    }

    mysql_query(&mysql_con,"commit");
    return true;

}
//注册
void Event_Recv::ZC_User()
{
    string user_tel = val["user_tel"].asString();
    string user_name = val["user_name"].asString();
    string user_passwd = val["user_passwd"].asString();

    //存mysql
    Mysql_Cli mysqlcli;
    if(!mysqlcli.Connect_Mysql_Ser("root","123456","localhost","c2209db",3306))
    {
        Send_ERR();
        return ;
    }
    if(!mysqlcli.Mysql_ZC_User(user_tel,user_name,user_passwd))
    {
        Send_ERR();
        return ;
    }
    Send_OK();
    return ;
}

void Event_Recv::DL_User()
{
    string user_tel = val["user_tel"].asString();
    string user_passwd = val["user_passwd"].asString();
    string user_name;

    Mysql_Cli mysqlcli;
    if(!mysqlcli.Connect_Mysql_Ser("root","123456","localhost","c2209db",3306))
    {
        Send_ERR();
        return ;
    }
    if(!mysqlcli.Mysql_DL_User(user_tel,user_passwd,user_name))
    {
        Send_ERR();
        return ;
    }

    Json::Value res_val;
    res_val["status"] = "OK";
    res_val["user_name"] = user_name;

    send(c,res_val.toStyledString().c_str(),strlen(val.toStyledString().c_str()),0);
    return ;
}

void Event_Recv::CK_Ticket()
{
    Json::Value res_val;
    Mysql_Cli mysqlcli;
    if(!mysqlcli.Connect_Mysql_Ser("root","123456","localhost","c2209db",3306))
    {
        Send_ERR();
        return ;
    }
    if(!mysqlcli.Mysql_CK_Ticket(res_val))
    {
        Send_ERR();
        return ;
    }
    
    send(c,res_val.toStyledString().c_str(),strlen(res_val.toStyledString().c_str()),0);
    return ;
}

void Event_Recv::YD_Ticket()
{
    string user_tel = val["user_tel"].asString();
    string tk_id = val["tk_id"].asString();

    Mysql_Cli mysqlcli;
    if(!mysqlcli.Connect_Mysql_Ser("root","123456","localhost","c2209db",3306))
    {
        Send_ERR();
        return ;
    }
    if(mysqlcli.Mysql_YD_Ticket(user_tel,tk_id))
    {
        Send_OK();
    }
    else
    {
        Send_ERR();
    }
}
void Event_Recv::CKYY_User()
{
    string tel = val["user_tel"].asString();
    Mysql_Cli mysqlcli;
    if(!mysqlcli.Connect_Mysql_Ser("root","123456","localhost","c2209db",3306))
    {
        Send_ERR();
        return ;
    }
    Json::Value res_val;
    if(!mysqlcli.Mysql_CKYY_User(tel,res_val))
    {
        Send_ERR();
        return ;
    }

    send(c,res_val.toStyledString().c_str(),strlen(res_val.toStyledString().c_str()),0);
}
void Event_Recv::QXYY_User()
{
    string yd_id = val["yd_id"].asString();
    Mysql_Cli mysqlcli;
    if(!mysqlcli.Connect_Mysql_Ser("root","123456","localhost","c2209db",3306))
    {
        Send_ERR();
        return ;
    }
    if(mysqlcli.Mysql_QXYY_User(yd_id))
    {
        Send_OK();
    }
    else
    {
        Send_ERR();
        return ;
    }
}

void Event_Recv::Send_OK()
{
    Json::Value res_val;
    res_val["status"] = "OK";

    send(c,res_val.toStyledString().c_str(),strlen(res_val.toStyledString().c_str()),0);
}
void Event_Recv::Send_ERR()
{
    Json::Value res_val;
    res_val["status"] = "ERR";

    send(c,res_val.toStyledString().c_str(),strlen(res_val.toStyledString().c_str()),0);
}


int Socket_Ser::Socket_Init()
{
    sockfd = socket(AF_INET,SOCK_STREAM,0);
    if( sockfd == -1 )
    {
        return -1;
    }

    struct sockaddr_in saddr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(ser_port);
    saddr.sin_addr.s_addr = inet_addr(ser_ips.c_str());

    int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if( res == -1 )
    {
        return -1;
    }

    res = listen(sockfd,TCP_LISTEN_MAX);
    if( res == -1 )
    {
        return -1;
    }

    return sockfd;
}

bool MyLibevent::Libevent_Add(int fd,Event_Obj* pObj)
{
    if( fd == -1 || pObj == NULL )
    {
        return false;
    }

    //初始化事件
    struct event* p_ev = event_new(m_base,fd,EV_READ|EV_PERSIST,G_CALLBACK_FUN,pObj);
    if(p_ev == nullptr)
    {
        return false;
    }
    pObj->ev = p_ev;
    event_add(p_ev,NULL);
    return true;
}

//event_accept类
void Event_Accept::Event_Callback()
{
    int c = accept(sockfd,NULL,NULL);
    if( c < 0 )
    {
        return ;
    }

    if( m_plib != nullptr )
    {
        Event_Recv* p = new Event_Recv(c);
        if( p == nullptr )
        {
            close(c);
        }
        m_plib->Libevent_Add(c,p);
    }
}

//event_recv类
void Event_Recv::Event_Callback()
{
    char buff[512] = {0};
    int n = recv(c,buff,511,0); //接收客户端报文
    if( n <= 0 )
    {
        event_free(ev);
        delete this;
        return ;
    }

    //test
    cout<<buff<<endl; //json格式字符串

    val.clear();
    Json::Reader Read;
    Read.parse(buff,val); //json格式字符串反序列化为json对象
    int op = val["type"].asInt();

    switch(op)
    {
        case ZC:
            ZC_User();
            break;
        case DL:
            DL_User();
            break;
        case CK:
            CK_Ticket();
            break;
        case YD:
            YD_Ticket();
            break;
        case CKYY:
            CKYY_User();
            break;
        case QX:
            QXYY_User();
            break;
        default:
            break;
    }
    
    // val.clear();
    // val["status"] = "OK";

    // send(c,val.toStyledString().c_str(),strlen(val.toStyledString().c_str()),0);
}


int main()
{
    Socket_Ser ser;
    if( ser.Socket_Init() == -1 )
    {
        cout<<"sockfd init failed"<<endl;
        exit(1);
    }

    MyLibevent* plib = new MyLibevent();
    if( plib == nullptr )
    {
        cout<<"create libevent error"<<endl;
        exit(1);
    }

    if( !plib->Libevent_Init())
    {
        cout<<"init_libevent error"<<endl;
        exit(1);
    }
 
    Event_Accept sock(ser.Get_Sockfd(),plib);
    plib->Libevent_Add(ser.Get_Sockfd(),&sock);

    plib->Libevent_base_dispatch();

    return 0;
} 